use std::collections::*;

use craftdig_core::registrar::BlockRegistry;
use craftdig_core::registrar::MsgTyRegistry;
use craftdig_datamodel::block;
use craftdig_datamodel::block::behaviors::*;
use craftdig_datamodel::block::model::*;
use craftdig_datamodel::block::ty::*;
use craftdig_datamodel::message::MsgTyReg;
use craftdig_datamodel::message::{MsgHandlerImpl, MsgTyId};
use craftdig_math::{Vec3f, AABB};

pub fn make_block_ty_registry() -> BlockRegistry {
    let mut reg = BlockRegistry::new();

    // TODO macro this

    // ID 0
    reg.register(
        "air".to_owned(),
        BlockData::new_simple("air", BlockModel::new_empty()).into(),
    );

    // ID 1
    reg.register(
        "stone".to_owned(),
        BlockData::new_simple("stone", BlockModel::new_simple(TexTable::new_simple(1))).into(),
    );

    // ID 2
    reg.register(
        "grass".to_owned(),
        BlockData::new_simple(
            "grass",
            BlockModel::new_simple(TexTable::new_upright(0, 3, 2)),
        )
        .into(),
    );

    // ID 3
    reg.register(
        "dirt".to_owned(),
        BlockData::new_simple("dirt", BlockModel::new_simple(TexTable::new_simple(2))).into(),
    );

    // ID 4
    reg.register(
        "cobblestone".to_owned(),
        BlockData::new_simple(
            "cobblestone",
            BlockModel::new_simple(TexTable::new_simple(16)),
        )
        .into(),
    );

    // ID 5
    reg.register(
        "wood_planks".to_owned(),
        BlockData::new_simple(
            "wood_planks",
            BlockModel::new_simple(TexTable::new_simple(4)),
        )
        .into(),
    );

    // ID 6 (should be 17)
    reg.register(
        "wood".to_owned(),
        BlockData::new_simple(
            "wood",
            BlockModel::new_simple(TexTable::new_upright(0x15, 0x14, 0x15)),
        )
        .into(),
    );

    // ID 7
    reg.register(
        "bedrock".to_owned(),
        BlockData::new_simple(
            "bedrock",
            BlockModel::new_simple(TexTable::new_simple(0x11)),
        )
        .into(),
    );

    // ID 8 (should be 43)
    reg.register(
        "full_smooth_stone_slab".to_owned(),
        BlockData::new_simple(
            "full_smooth_stone_slab_full",
            BlockModel::new_simple(TexTable::new_upright(6, 5, 6)),
        )
        .into(),
    );

    // ID 9 (should be 44)
    let slab_aabb = AABB::new(Vec3f::zero(), Vec3f::new(1.0, 0.5, 1.0));
    reg.register(
        "smooth_stone_slab".to_owned(),
        BlockData::new_simple(
            "smooth_stone_slab",
            BlockModel::new(
                Solidity::Transparent,
                slab_aabb,
                Collider::Cubic(slab_aabb),
                Shape::Cubic {
                    aabb: slab_aabb,
                    texes: TexTable::new_upright(6, 5, 6),
                },
                Color::from((255, 255, 255)),
            ),
        )
        .into(),
    );

    // ID 10 (should be 12)
    let mut sand_handlers = HashMap::new();
    let sand_onpl = MsgHandlerImpl::new(fallingsand::FsPlaceBehavior);
    let sand_onnu = MsgHandlerImpl::new(fallingsand::FsUpdateBehavior);
    sand_handlers.insert(MsgTyId::from(0), sand_onpl); // FIXME don't hardcode
    sand_handlers.insert(MsgTyId::from(2), sand_onnu); // FIXME don't hardcode
    reg.register(
        "sand".to_owned(),
        BlockData::new(
            "sand".to_owned(),
            sand_handlers,
            BlockModel::new_simple(TexTable::new_simple(0x12)),
        )
        .into(),
    );

    // ID 11 (should be 13)
    let mut gravel_handlers = HashMap::new();
    let gravel_onpl = MsgHandlerImpl::new(fallingsand::FsPlaceBehavior);
    let gravel_onnu = MsgHandlerImpl::new(fallingsand::FsUpdateBehavior);
    gravel_handlers.insert(MsgTyId::from(0), gravel_onpl); // FIXME don't hardcode
    gravel_handlers.insert(MsgTyId::from(2), gravel_onnu); // FIXME don't hardcode
    reg.register(
        "gravel".to_owned(),
        BlockData::new(
            "gravel".to_owned(),
            gravel_handlers,
            BlockModel::new_simple(TexTable::new_simple(0x13)),
        )
        .into(),
    );

    // ID 12 (should be 48)
    reg.register(
        "mossy_cobblestone".to_owned(),
        BlockData::new_simple(
            "mossy_cobblestone",
            BlockModel::new_simple(TexTable::new_simple(0x24)),
        )
        .into(),
    );

    reg
}

pub fn make_msg_ty_registry() -> MsgTyRegistry {
    use block::msgs::*;

    let mut reg = MsgTyRegistry::new();

    reg.register("onplace".to_owned(), MsgTyReg::new::<OnPlaceMessage>());
    reg.register("onbreak".to_owned(), MsgTyReg::new::<PreBreakMessage>());
    reg.register(
        "update".to_owned(),
        MsgTyReg::new::<NeighborUpdateMessage>(),
    );

    reg
}
